/*
 * Copyright (C) 2005 Johan Maasing johan at zoom.nu Licensed under the Apache
 * License, Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package nu.zoom.swing.desktop.frame;

import java.awt.event.ActionEvent;
import java.util.HashMap;

import javax.swing.JMenu;
import javax.swing.JMenuItem;

import nu.zoom.swing.desktop.WorkbenchFrame;
import nu.zoom.swing.desktop.WorkbenchMenuBar;
import nu.zoom.swing.desktop.common.action.DetachAction;
import nu.zoom.swing.desktop.common.action.WorkbenchMessageAction;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.ops4j.gaderian.Messages;

/**
 * 
 * @author "Johan Maasing" &lt;johan@zoom.nu&gt;
 * 
 */
class WorkbenchFramesMenu {

	private Log log = LogFactory.getLog(getClass());
	private JMenu windowMenu;
	private HashMap<WorkbenchFrame, JMenu> frameMenues;
	private static String MENU_KEY = "WindowMenu";
	private final Messages messages;

	WorkbenchFramesMenu(final Messages messages, final WorkbenchMenuBar menuBar) {
		this.messages = messages;
		frameMenues = new HashMap<WorkbenchFrame, JMenu>();
		windowMenu = new JMenu(messages.getMessage("menu.window"));
		windowMenu.setMnemonic('w');
		menuBar.addMenu(MENU_KEY, windowMenu);
	}

	/**
	 * Must be called on the EventQueue
	 * 
	 * @param frame
	 *            The frame that is added to the desktop
	 */
	synchronized void addFrame(final WorkbenchFrame frame) {
		log.trace("Trying to add frame to window menu");
		if (frame.getTitle().length() > 0) {
			log.trace("frame title exists - adding frame to menu");
			JMenu frameMenu = createFrameMenu(frame);
			frameMenues.put(frame, frameMenu);
			windowMenu.add(frameMenu);
		}
	}

	/**
	 * Must be called on the eventqueue.
	 * 
	 * @param frame
	 *            The frame that is removed from the desktop
	 */
	synchronized void removeFrame(final WorkbenchFrame frame) {
		if (frame != null) {
			log.trace("Removing frame from menu");
			JMenu itemToRemove = frameMenues.get(frame);
			if (itemToRemove != null) {
				windowMenu.remove(itemToRemove);
			}
			frameMenues.remove(frame);
		}
	}

	/**
	 * Must be called on the eventqueue. Drops all references to frames.
	 */
	synchronized void clear() {
		log.trace("Dropping references to all frames");
		frameMenues.clear();
		windowMenu.removeAll();
	}

	private JMenu createFrameMenu(WorkbenchFrame frame) {
		JMenu frameMenu = new JMenu(frame.getTitle());
		JMenuItem frontItem = new JMenuItem(new FrameToFrontAction(messages, frame));
		JMenuItem detachItem = new JMenuItem(new DetachAction(frame) {
			private static final long serialVersionUID = -1137756047135872634L;

			@Override
			protected void setAttachedLook() {
				setName(messages.getMessage("menu.window.detach"));
				setToolTip(messages.getMessage("menu.window.detach.tooltip"));
			}

			@Override
			protected void setDetachedLook() {
				setName(messages.getMessage("menu.window.attach"));
				setToolTip(messages.getMessage("menu.window.attach.tooltip"));
			}
		});
		frameMenu.add(frontItem);
		frameMenu.add(detachItem);
		return frameMenu;
	}

	@SuppressWarnings("serial")
	class FrameToFrontAction extends WorkbenchMessageAction {

		private WorkbenchFrame frame;

		FrameToFrontAction(Messages messages, WorkbenchFrame frame) {
			super(messages);
			setNameFromMessages("menu.window.tofront");
			this.frame = frame;
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			if (!frame.isVisible()) {
				log.trace("Making frame visible");
				frame.setVisible(true);
			}
			log.trace("Moving frame to front");
			frame.moveToFront();
		}
	}
}
